package com.btm.qiaoqiang.ruleadp.parser;

import com.btm.qiaoqiang.ruleadp.CheckTarget;
import com.btm.qiaoqiang.ruleadp.CustomDynamicComparator;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * 值检查
 */
@Slf4j
public class ValueCheck {

    public final CustomDynamicComparator customDynamicComparator;

    public ValueCheck(CustomDynamicComparator customDynamicComparator) {
        this.customDynamicComparator = customDynamicComparator;
    }

    /**
     * 检验当前节点是否满足条件
     *
     * @param object 给定的待检测对象
     * @return
     */
    public boolean check(RuleNode ruleNode, Object object) {
        try {
            Object rv;
            if (object instanceof CheckTarget) {
                rv = ((CheckTarget) object).getValue(ruleNode.getFieldName(), ruleNode.getValue());
            } else {
                Class clazz = object.getClass();
                Method method = clazz.getMethod(ruleNode.getMethodName());
                method.setAccessible(true);
                rv = method.invoke(object);
            }
            //取值字段没有值则无法匹配，所以返回false
            if (Objects.isNull(rv)) {
                log.warn("字段\"{}\"为空，匹配失败", ruleNode.getFieldName());
                return false;
            }
            if (ruleNode.isCustomDynamicValue()) {
                if (!customDynamicComparator.check(ruleNode.getValue(), rv)) {
                    log.warn("字段\"{}\"自定义校验，期望值[{}]，实际值[{}]，匹配失败", ruleNode.getFieldName(), ruleNode.getValue(), rv);
                    return false;
                }
            } else if (ruleNode.isEqual()) {
                if (ruleNode.isValueTypeIsNumber()) {
                    Double rvn = Double.valueOf(String.valueOf(rv));
                    Double vn = Double.valueOf(String.valueOf(ruleNode.getValue()));
                    if (rvn.compareTo(vn) != 0) {
                        log.warn("字段\"{}\"等值校验，期望值[{}]，实际值[{}]，两者不相等，匹配失败", ruleNode.getFieldName(), vn, rvn);
                        return false;
                    }
                } else {
                    String rvn = String.valueOf(rv);
                    String vn = String.valueOf(ruleNode.getValue());
                    if (!rvn.equals(vn)) {
                        log.warn("字段\"{}\"等值校验，期望值[{}]，实际值[{}]，两者不一致，匹配失败", ruleNode.getFieldName(), vn, rvn);
                        return false;
                    }
                }
            } else if (ruleNode.isNotEqual()) {
                if (ruleNode.isValueTypeIsNumber()) {
                    Double rvn = Double.valueOf(String.valueOf(rv));
                    Double vn = Double.valueOf(String.valueOf(ruleNode.getValue()));
                    if (rvn.compareTo(vn) == 0) {
                        log.warn("字段\"{}\"不相等校验，期望值[{}]，实际值[{}]，两者相等，匹配失败", ruleNode.getFieldName(), vn, rvn);
                        return false;
                    }
                } else {
                    String rvn = String.valueOf(rv);
                    String vn = String.valueOf(ruleNode.getValue());
                    if (rvn.equals(vn)) {
                        log.warn("字段\"{}\"不一致校验，期望值[{}]，实际值[{}]，两者一致，匹配失败", ruleNode.getFieldName(), vn, rvn);
                        return false;
                    }
                }
            } else if (ruleNode.isGt()) {
                if (!ruleNode.isValueTypeIsNumber()) {
                    throw new RuntimeException("error value type, need a number, but not found");
                }
                Double rvn = Double.valueOf(String.valueOf(rv));
                Double vn = Double.valueOf(String.valueOf(ruleNode.getValue()));
                if (rvn.compareTo(vn) <= 0) {
                    log.warn("字段\"{}\"小于等于校验，期望值[{}]，实际值[{}]，期望值大于实际值，匹配失败", ruleNode.getFieldName(), vn, rvn);
                    return false;
                }
            } else if (ruleNode.isGte()) {
                if (!ruleNode.isValueTypeIsNumber()) {
                    throw new RuntimeException("error value type, need a number, but not found");
                }
                Double rvn = Double.valueOf(String.valueOf(rv));
                Double vn = Double.valueOf(String.valueOf(ruleNode.getValue()));
                if (rvn.compareTo(vn) < 0) {
                    log.warn("字段\"{}\"小于校验，期望值[{}]，实际值[{}]，期望值大于等于实际值，匹配失败", ruleNode.getFieldName(), vn, rvn);
                    return false;
                }
            } else if (ruleNode.isLt()) {
                if (!ruleNode.isValueTypeIsNumber()) {
                    throw new RuntimeException("error value type, need a number, but not found");
                }
                Double rvn = Double.valueOf(String.valueOf(rv));
                Double vn = Double.valueOf(String.valueOf(ruleNode.getValue()));
                if (rvn.compareTo(vn) >= 0) {
                    log.warn("字段\"{}\"大于等于校验，期望值[{}]，实际值[{}]，期望值小于实际值，匹配失败", ruleNode.getFieldName(), vn, rvn);
                    return false;
                }
            } else if (ruleNode.isLte()) {
                if (!ruleNode.isValueTypeIsNumber()) {
                    throw new RuntimeException("error value type, need a number, but not found");
                }
                Double rvn = Double.valueOf(String.valueOf(rv));
                Double vn = Double.valueOf(String.valueOf(ruleNode.getValue()));
                if (rvn.compareTo(vn) > 0) {
                    log.warn("字段\"{}\"大于校验，期望值[{}]，实际值[{}]，期望值小于等于实际值，匹配失败", ruleNode.getFieldName(), vn, rvn);
                    return false;
                }
            } else if (ruleNode.getValue() instanceof Boolean) {
                if (ruleNode.getValue().equals(rv)) {
                    //nothing to do.
                } else {
                    log.warn("字段\"{}\"boolean等值校验，期望值[{}]，实际值[{}]，匹配失败", ruleNode.getFieldName(), ruleNode.getValue(), rv);
                    return false;
                }
            } else {
                throw new RuntimeException("error expression");
            }
            for (RuleNode nextRuleNode : ruleNode.getChildNodeList()) {
                if (this.check(nextRuleNode, object)) {
                    return true;
                }
            }
            // 正常情况下不会走到这里，只有走到规则树分支的最后才会进到这里时说明校验正确，其他情况走到这里说明校验失败
            return ruleNode.isLeafNode();
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("not found method [" + ruleNode.getMethodName() + "]", e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("the method [" + ruleNode.getMethodName() + "] error: IllegalAccessException", e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("the method [" + ruleNode.getMethodName() + "] error: InvocationTargetException", e);
        }
    }

}
